#include <windows.h>
#include"resource.h"
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <ctype.h>

const char g_szClassName[] = "myWindowClass";
HINSTANCE hInst;

 HDC hdc;
 int xx,yy,a,b;


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////		COD HUFFMAN CONSOLA		//////////////////////////////////////////////

typedef struct lista{
	char cheie;
	int K;
	int d;
	int L;
	int frecventa;
	lista *next,*left,*right;
	char cod[10];
}lista;

int x=0;
lista *first=NULL,*auxfirst=NULL,*p=first;
int nivel=0;
char sip[128]={""},V[2]={""};
void inserare(lista *chek);
int putere(int baza,int exponent){
	int rezultat=1;
	for(int ib=1;ib<=exponent;ib++)
		rezultat=rezultat*baza;
	return rezultat;
}
void frecventa(char s[128])
{
	lista *l=NULL;
	char freq[256]={0};
	for (int i=0;i<strlen(s);i++)
	freq[int(s[i])]++;
	for (int i=0;i<256;i++)
	{
		if(freq[i]!=0)
		{
			l=(lista*)malloc(sizeof(lista));
			l->cheie=char(i);
			l->frecventa=freq[i];
			l->next=NULL;
			l->right=l->left=NULL;
			inserare(l);
			
		}
	}
	for (l=first;l->next!=NULL;l=l->next)
		auxfirst=first;}
void inserare(lista *chek)
{
	lista *p;
	if (first==NULL) {first=chek;chek->next=NULL; return;}
	if (first->frecventa>chek->frecventa)
	{
		chek->next=first;
		first=chek;return;
	}
	for (p=first;p->next!=NULL;p=p->next)
		if (p->next->frecventa>chek->frecventa)
		{
		  chek->next=p->next;
		  p->next=chek;break;
		}
		if (p->next==NULL) 
		{
			p->next=chek;
			chek->next=NULL;
		}
}
void TrListToTree()
{
	lista *q,*p;
	p=first;
	while (p->next!=NULL)
	{
		q=(lista*)malloc(sizeof(lista));
		q->cheie='*';
		q->frecventa=p->frecventa+p->next->frecventa;
		q->left=p;
		q->right=p->next;
		q->next=NULL;
		if (p->next->next!=NULL)
		{
		 first=p->next->next;
		 inserare(q);
		 p=first;
		}
		else {first=q;break;}
	}
}
void parcurgere(lista *p,lista *dad,char c[10])
{
	if (p==NULL) 
			parcurgere(dad,dad,"");
	else if (p==dad)
	{
		strcpy(dad->cod,c);
		parcurgere(p->left,p,"0");
		parcurgere(p->right,p,"1");
	}
	else
		{   
			strcpy (p->cod,dad->cod);
			strcat(p->cod,c);
			if (p->left!=NULL && p->right!=NULL)
			{
				parcurgere(p->left,p,"0");
				parcurgere(p->right,p,"1");
			}					
		}

}
char* decompression(lista *p,char spor[512])
{
	while(x<=strlen(spor))
  {
	  char c=spor[x];
	  if (p->left!=NULL && p->right!=NULL)
		  {
			  x++;
			  if (c=='0') decompression(p->left,spor); 
			  else  if (c=='1') decompression(p->right,spor);
			}
	  else if (p->cheie!=42) 
	  {
		  V[0]=p->cheie;	
		  strcat(sip,V);			
		  p=first;
	  }
  }
	return sip;
}
char* compression(char text[])
{	
	lista *p=first;
	char H[512]={""};
	frecventa(text);
	TrListToTree();
	char c[10]={""};
	parcurgere(p,first,c);
	for(int i=0;i<strlen(text);i++)
	{
		p=auxfirst;
		while(p!=NULL)
		{
			if(text[i]==p->cheie)
			{
				strcat(H,p->cod);
				break;
			}
			p=p->next;
		}
	}
	return H;
}
void freeTree(lista *root)
{            
	while(1){		
		if(root == NULL){
			break;
		}
		else if(root->left != NULL){
			freeTree(root->left);
			root->left=NULL;
		}
		else if(root->right != NULL){
			freeTree(root->right);
			root->right=NULL;
		}
		else{ 
                        free(root);
			return;
		}
	}
}
void  pozitie(lista *root){
	if(root==NULL) return;
	else{
		first->K=1;
		first->d=0;
		if(root!=NULL && root->left!=NULL)		{
			root->left->d=root->K-1;
			root->left->K=root->K+root->left->d;
			pozitie(root->left);
			pozitie(root->right);
		}
		if(root!=NULL && root->right!=NULL)		{
			root->right->d=root->K;
			root->right->K=root->K+root->right->d;
			pozitie(root->left);
			pozitie(root->right);
		}
	}
}
void level(lista *root){
	if(root==NULL) return;
	else{
		first->L=1;
		if(root!=NULL){
			nivel++;
			root->L=nivel;
			level(root->left);
			level(root->right);
			nivel--;
		}
	}
}
void desenarelinie(int x1,int y1,int x2,int y2);
void desenare(int L,int K,char cheie)
{
	int D=820; char CH[2];
	if(K==1){
		for(int iL=1;iL<=L;iL++)
			D=(D-10)/2;
		Rectangle(hdc,D,L*80,D+20,L*80+20);
		CH[0]=cheie;			CH[1]=NULL;
		TextOut(hdc,D+6,L*80+2,CH,1);
		xx=D+6;
		yy=L*80+2;
		return;
	}
	for(int iL=1;iL<=L;iL++)
			D=(D-10)/2;
	int Di=D;
	for(int iK=2;iK<=K;iK++)
		Di=Di+20+2*D+2;
	Rectangle(hdc,Di,L*80,Di+20,L*80+20);
	CH[0]=cheie;			CH[1]=NULL;
	TextOut(hdc,Di+5,L*80+2,CH,1);
	xx=Di+5;
	yy=L*80+2;
}
void desenarelinie(int x1,int y1,int x2,int y2)
{
	//HPE
	POINT coord[2];
	coord[0].x=x1;
	coord[0].y=y1;
	coord[1].x=x2;
	coord[1].y=y2;
	Polyline(hdc,coord,2);
}
void desenare_arbore(lista *root)
{
	int i;	
	if (root==NULL) return;			
		desenare(root->L,root->K,root->cheie);
		a=xx;b=yy;
	if(root->left!=NULL && root->right!=NULL){
		desenare(root->left->L,root->left->K,root->left->cheie);
		desenarelinie(xx,yy,a-5,b+15);
		TextOut(hdc,(xx+a)/2,(yy+b)/2,"0",1);
		desenare(root->right->L,root->right->K,root->right->cheie);
		desenarelinie(xx,yy,a+10,b+15);
		TextOut(hdc,(xx+a)/2,(yy+b)/2,"1",1);
	}
	desenare_arbore(root->left);		
	desenare_arbore(root->right);		
	a=xx;			b=yy;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////		TREE	 DIALOG		//////////////////////////////////////////////////////////////////
BOOL CALLBACK treeDlg(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	int posX, posY, ipr, D, Dip, L=0, Di, c=20;
	switch(Message)
    {		
		 PAINTSTRUCT ps;
        case WM_INITDIALOG:			return TRUE;
        case WM_COMMAND:
			{}		break;
		case WM_PAINT:
          hdc = BeginPaint(hwnd, &ps);
		  desenare_arbore(first);
		 /*D=820;
       	 for(posY=80;posY<800;posY+=80){
				 if(D<5) break;  
				 D=(D-10)/2;//D - distanta pentru primul patrat
				 Rectangle(hdc, D,posY,D+20, posY+20);//desenare primul patrat
				 Di=D;
				 for(ipr=1;ipr<=(putere(2,L)-1);ipr++){//nr de patrate ramase de desenat
					 Di=Di+c+2*D+2;
					 Rectangle(hdc, Di,posY,Di+20, posY+20);//desenare patrate ramase
				 }
				 L++;	 //creste nivelul in arbore
			 }*/
          EndPaint(hwnd, &ps);
          break;
		case WM_CLOSE:			EndDialog(hwnd, 0);			return TRUE;
		default:			return FALSE;
    }
    return TRUE;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////		ENCODE TEXT DALOG			//////////////////////////////////////////////////
BOOL CALLBACK ToolDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	char text[128];		char vfinal[128];			char D[512];
	switch(Message)
    {
	case WM_INITDIALOG:
		SetDlgItemText(hwnd,IDC_EDIT1,"Enter text to encode here(max. 128 characters)");
			break;
		case WM_COMMAND:
            switch(LOWORD(wParam))
            {
			case IDC_BUTTON2:
				{
					GetDlgItemText(hwnd,IDC_EDIT1,text,128);
					strcpy(D,compression(text));
					MessageBox(NULL,"Text encoded!","Info",MB_OK);
					SetDlgItemText(hwnd, IDC_EDIT2,D);
				}			break;
			case IDC_BUTTON1:
				{
					GetDlgItemText(hwnd,IDC_EDIT2,D,512);
					strcpy(vfinal,decompression(first,D));
					SetDlgItemText(hwnd,IDC_EDIT3,vfinal);
					MessageBox(NULL,"Text decoded!","Info",MB_OK);
				}			break;
			case IDC_BUTTON3:		{pozitie(first);  level(first);	EndDialog(hwnd, 0);		}	break;
			case IDC_BUTTON4:		
				{
					freeTree(first); 
					strcpy(text,"");
					strcpy(D,"");
					first=NULL;
					p=first;
					strcpy(vfinal,"");
					strcpy(sip,"");
					x=0;
					SetDlgItemText(hwnd, IDC_EDIT2,"");
					SetDlgItemText(hwnd,IDC_EDIT3,"");
					SetDlgItemText(hwnd, IDC_EDIT1,"");
				}			break;
			}			break;
		case WM_CLOSE:			{pozitie(first);  level(first);	EndDialog(hwnd, 0); EndDialog(hwnd, 0);}			return TRUE;
        default:			return FALSE;
    }
    return TRUE;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////		ABOUT	 DIALOG		//////////////////////////////////////////////////////////////
BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	switch(Message)
    {
        case WM_INITDIALOG:			return TRUE;
        case WM_COMMAND:
            switch(LOWORD(wParam))
            {
				case IDOK:
                    EndDialog(hwnd, IDOK);			break;
			}			break;
			default:			return FALSE;
		case WM_CLOSE:			EndDialog(hwnd, 0);			return TRUE;
    }
    return TRUE;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////		MAIN WINDOW		//////////////////////////////////////////////////////////////////	
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	HDC hDC, MemDCExercising;
    PAINTSTRUCT Ps;
    HBITMAP bmpExercising;

    switch(msg)
    {
		case WM_PAINT:
		{
			hDC = BeginPaint(hwnd, &Ps);	   
			bmpExercising = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP2)); // Load the bitmap from the resource
	        MemDCExercising = CreateCompatibleDC(hDC);// Create a memory device compatible with the above DC variable
            SelectObject(MemDCExercising, bmpExercising); // Select the new bitmap
			BitBlt(hDC, 0, 0, 640, 395, MemDCExercising, 0, 0, SRCCOPY); // Copy the bits from the memory DC into the current dc			
		}			break;
		case WM_COMMAND:
			switch(LOWORD(wParam))
			{
				case ID_FILE_EXIT:			PostMessage(hwnd, WM_CLOSE, 0, 0);			break;
				case ID_ACTIONS_ENCODEMESSAGE:			DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG2), hwnd, ToolDlgProc);			break;
				case ID_ACTIONS_DEMONTRATOR:			DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG3), hwnd, treeDlg);			break;
				case ID_HELP_ABOUT:			DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), hwnd, AboutDlgProc);			break;
			} break;
        case WM_CLOSE:			DestroyWindow(hwnd);				break;
        case WM_DESTROY:			PostQuitMessage(0);			break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX  WndCls;
	HWND hwnd;
    MSG         Msg;
	static char szAppName[] = "Huffman Coding Demonstrator";

	hInst       = hInstance;
    WndCls.cbSize        = sizeof(WndCls);
    WndCls.style         = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
    WndCls.lpfnWndProc   = WndProc;
    WndCls.cbClsExtra    = 0;
    WndCls.cbWndExtra    = 0;
    WndCls.hInstance     = hInst;
     WndCls.hIcon         =  LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON1));
    WndCls.hCursor       =  LoadCursor(hInstance,MAKEINTRESOURCE(IDC_CURSOR1));
    WndCls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	WndCls.lpszMenuName  = MAKEINTRESOURCE(IDR_MENU1);
    WndCls.lpszClassName = szAppName;
    WndCls.hIconSm       = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON1));
    RegisterClassEx(&WndCls);
	
	 hwnd=CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, szAppName,"Huffman Coding Demonstrator",WS_OVERLAPPEDWINDOW | WS_VISIBLE,0, 0, 658, 458,NULL, NULL, hInstance, NULL);
    
    while( GetMessage(&Msg, NULL, 0, 0) )
    {
        TranslateMessage(&Msg);
        DispatchMessage( &Msg);
    }

    return static_cast<int>(Msg.wParam);
}
